/**
 * 
 */
package edu.umd.clip.lm.ngram;

import java.util.Arrays;


public abstract class Ngram {
	long future;
	
	public Ngram(long future) {
		this.future = future;
	}

	public static Ngram makeNgram(int order, long[] context, long future) {
		if (order == 1) {
			return new Unigram(future);
		}
		
		int first = context.length - order + 1;
		if (order == 7) {
			return new Sevengram(context[first], context[first+1], context[first+2], context[first+3], context[first+4], context[first+5], future);
		} else if (order == 6) {
			return new Sixgram(context[first], context[first+1], context[first+2], context[first+3], context[first+4], future);
		} else if (order == 5) {
			return new Fivegram(context[first], context[first+1], context[first+2], context[first+3], future);
		} else if (order == 4) {
			return new Fourgram(context[first], context[first+1], context[first+2], future);
		} else if (order == 3) {
			return new Trigram(context[first], context[first+1], future);
		} else if (order == 2) {
			return new Bigram(context[first], future);
		}
		throw new Error("Bad context lengths: " + context.length);
	}
	
	public static Ngram makeNgram(long[] context) {
		return makeNgram(Arrays.copyOf(context, context.length-1), context[context.length-1]);
	}
	
	public static Ngram makeNgram(long[] context, long future) {
		if (context == null || context.length == 0) {
			return new Unigram(future);
		} else if (context.length == 3) {
			return new Fourgram(context, future);
		} else if (context.length == 2) {
			return new Trigram(context, future);
		} else if (context.length == 1) {
			return new Bigram(context, future);
		} 
		throw new Error("Bad context lengths: " + context.length);
	}
	
	public abstract int getOrder();
	public abstract long[] getContext();
	public abstract Ngram getLowerOrderNgram();
	
	public long getFuture() {
		return future;
	}
	
	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + (int) (future ^ (future >>> 32));
		return result;
	}
	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (!(obj instanceof Ngram))
			return false;
		Ngram other = (Ngram) obj;
		if (future != other.future)
			return false;
		return true;
	}
}